package org.cybzacg.convert.core;


import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.cybzacg.convert.context.ConversionContext;
import org.cybzacg.convert.context.impl.DefaultConversionContext;
import org.cybzacg.convert.enums.ConversionError;
import org.cybzacg.convert.enums.ConversionPriority;
import org.cybzacg.convert.enums.ConversionStrategyEnum;
import org.cybzacg.convert.enums.ConversionType;
import org.cybzacg.convert.exception.ConversionException;
import org.cybzacg.convert.listener.ConversionListener;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 抽象类型转换器基类
 * 提供转换器的公共实现和模板方法
 *
 * @author cybzacg.blog
 * @version 3.0
 * @since 3.0
 */
@Slf4j
public abstract class AbstractTypeConverter implements TypeConverter {

    public static final String STRING = "监听器通知失败";
    /**
     * 转换监听器列表
     */
    private final List<ConversionListener> listeners = new CopyOnWriteArrayList<>();

    /**
     * 转换器优先级
     */
    private final ConversionPriority priority;

    /**
     * 是否启用
     * -- SETTER --
     * 设置是否启用
     *
     * @param enabled 是否启用
     */
    @Setter
    private volatile boolean enabled = true;

    /**
     * 最大转换深度
     * -- GETTER --
     * 获取最大转换深度
     *
     * @return 最大转换深度
     */
    @Getter
    @Setter
    private int maxDepth = 10;

    protected AbstractTypeConverter(ConversionPriority priority) {
        this.priority = priority;
    }

    protected AbstractTypeConverter() {
        this(ConversionPriority.MEDIUM);
    }

    @Override
    public final <T> T convert(Object source, Class<T> targetType, T defaultValue) throws ConversionException {
        return convert(source, targetType, defaultValue, null);
    }

    @Override
    public final <T> T convert(Object source, Class<T> targetType) throws ConversionException {
        return convert(source, targetType, null, null);
    }

    /**
     * 带上下文的转换方法
     *
     * @param <T>          目标类型
     * @param source       源对象
     * @param targetType   目标类型
     * @param defaultValue 默认值
     * @param context      转换上下文
     * @return 转换结果
     * @throws ConversionException 转换失败时抛出
     */
    public final <T> T convert(Object source, Class<T> targetType, T defaultValue, ConversionContext context)
            throws ConversionException {

        // 创建上下文（如果未提供）
        if (context == null) {
            context = createContext(source != null ? source.getClass() : null, targetType);
        }

        // 设置源类型和目标类型
        context.setSourceType(source != null ? source.getClass() : null);
        context.setTargetType(targetType);
        context.setConversionType(ConversionType.fromTypeName(targetType.getSimpleName()));
        context.setDefaultValue(defaultValue);

        // 通知转换开始
        notifyConversionStart(context, source);

        try {
            // 检查转换深度
            if (context.isDepthExceeded(maxDepth)) {
                throw new ConversionException(ConversionError.DEPENDENCY_MISSING,
                        "转换深度超过限制: " + maxDepth);
            }

            // 增加转换深度
            context.incrementDepth();

            // 执行转换前的验证
            if (context.isValidationEnabled()) {
                validatePreConversion(context, source);
            }

            // 检查缓存
            if (context.isCacheEnabled()) {
                T cachedResult = getCachedResult(context, source);
                if (cachedResult != null) {
                    notifyCacheHit(context, source, cachedResult);
                    return cachedResult;
                }
                notifyCacheMiss(context, source);
            }

            // 执行实际转换
            T result = doConvert(source, targetType, defaultValue, context);

            // 执行转换后的验证
            if (context.isValidationEnabled()) {
                validatePostConversion(context, source, result);
            }

            // 缓存结果
            if (context.isCacheEnabled()) {
                cacheResult(context, source, result);
            }

            // 通知转换成功
            notifyConversionSuccess(context, source, result);
            notifyConversionComplete(context, source, result, null);

            return result;

        } catch (Exception e) {
            // 处理异常
            Exception handledException = handleException(context, source, e);

            // 通知转换失败
            notifyConversionFailure(context, source, handledException);
            notifyConversionComplete(context, source, null, handledException);

            // 根据策略决定是否抛出异常
            if (shouldThrowException(context, handledException)) {
                throw new ConversionException(ConversionError.fromException(handledException),
                        handledException.getMessage(), handledException);
            }

            // 返回默认值
            return defaultValue;
        } finally {
            // 减少转换深度
            context.setDepth(context.getDepth() - 1);
        }
    }

    /**
     * 执行实际的转换逻辑
     * 子类必须实现此方法
     *
     * @param <T>          目标类型
     * @param source       源对象
     * @param targetType   目标类型
     * @param defaultValue 默认值
     * @param context      转换上下文
     * @return 转换结果
     * @throws Exception 转换失败时抛出
     */
    protected abstract <T> T doConvert(
            Object source,
            Class<T> targetType,
            T defaultValue,
            ConversionContext context
    ) throws Exception;

    /**
     * 创建转换上下文
     *
     * @param sourceType 源类型
     * @param targetType 目标类型
     * @return 转换上下文
     */
    protected ConversionContext createContext(Class<?> sourceType, Class<?> targetType) {
        return new DefaultConversionContext();
    }

    /**
     * 转换前验证
     *
     * @param context 转换上下文
     * @param source  源对象
     * @throws Exception 验证失败时抛出
     */
    protected void validatePreConversion(ConversionContext context, Object source) throws Exception {
        notifyValidationStart(context, source);

        // 基本验证
        if (source == null && context.getStrategy().isStrict()) {
            throw new ConversionException(ConversionError.NULL_VALUE,
                    "严格模式下不允许空值转换");
        }

        notifyValidationSuccess(context, source);
    }

    /**
     * 转换后验证
     *
     * @param context 转换上下文
     * @param source  源对象
     * @param result  转换结果
     * @throws Exception 验证失败时抛出
     */
    protected void validatePostConversion(ConversionContext context, Object source, Object result) throws Exception {
        notifyValidationStart(context, result);

        // 基本验证
        if (result == null && context.getStrategy().isStrict()) {
            throw new ConversionException(ConversionError.NULL_VALUE,
                    "严格模式下转换结果不能为null");
        }

        notifyValidationSuccess(context, result);
    }

    /**
     * 获取缓存结果
     *
     * @param <T>     结果类型
     * @param context 转换上下文
     * @param source  源对象
     * @return 缓存结果
     */
    protected <T> T getCachedResult(ConversionContext context, Object source) {
        // 默认不使用缓存，子类可以重写
        return null;
    }

    /**
     * 缓存结果
     *
     * @param context 转换上下文
     * @param source  源对象
     * @param result  转换结果
     */
    protected void cacheResult(ConversionContext context, Object source, Object result) {
        // 默认不缓存，子类可以重写
    }

    /**
     * 处理异常
     *
     * @param context   转换上下文
     * @param source    源对象
     * @param exception 原始异常
     * @return 处理后的异常
     */
    protected Exception handleException(ConversionContext context, Object source, Exception exception) {
        // 默认直接返回原始异常，子类可以重写进行特殊处理
        return exception;
    }

    /**
     * 判断是否应该抛出异常
     *
     * @param context   转换上下文
     * @param exception 异常
     * @return 是否应该抛出异常
     */
    protected boolean shouldThrowException(ConversionContext context, Exception exception) {
        ConversionStrategyEnum strategy = context.getStrategy();

        // 严格模式总是抛出异常
        if (strategy.isStrict()) {
            return true;
        }

        // 宽松模式：对于不可恢复的错误抛出异常
        if (strategy.isLenient()) {
            return !ConversionError.fromException(exception).isRecoverable();
        }

        // 安全模式：对于严重错误抛出异常
        if (strategy.isSafe()) {
            return isSevereError(exception);
        }

        return false;
    }

    /**
     * 判断是否为严重错误
     *
     * @param exception 异常
     * @return 是否为严重错误
     */
    protected boolean isSevereError(Exception exception) {
        // 检查是否为安全相关错误
        if (exception instanceof SecurityException) {
            return true;
        }

        // 检查是否为格式错误或转换错误
        if (exception instanceof NumberFormatException ||
                exception instanceof IllegalArgumentException ||
                exception instanceof ConversionException) {
            return true;
        }

        // 检查错误消息是否包含严重关键词
        String message = exception.getMessage();
        if (message != null) {
            String lowerMessage = message.toLowerCase();
            return lowerMessage.contains("security") ||
                    lowerMessage.contains("access") ||
                    lowerMessage.contains("permission") ||
                    lowerMessage.contains("memory") ||
                    lowerMessage.contains("stack") ||
                    lowerMessage.contains("overflow") ||
                    lowerMessage.contains("format") ||
                    lowerMessage.contains("conversion") ||
                    lowerMessage.contains("parse");
        }

        return false;
    }

    @Override
    public boolean supports(Class<?> targetType) {
        return getSupportedConversionTypes().stream()
                .anyMatch(type -> {
                    // 根据转换类型检查是否支持目标类型
                    return switch (type) {
                        case STRING -> targetType == String.class;
                        case BOOLEAN -> targetType == Boolean.class || targetType == boolean.class;
                        case CHARACTER -> targetType == Character.class || targetType == char.class;
                        case BYTE -> targetType == Byte.class || targetType == byte.class;
                        case SHORT -> targetType == Short.class || targetType == short.class;
                        case INTEGER -> targetType == Integer.class || targetType == int.class;
                        case LONG -> targetType == Long.class || targetType == long.class;
                        case FLOAT -> targetType == Float.class || targetType == float.class;
                        case DOUBLE -> targetType == Double.class || targetType == double.class;
                        case BIG_DECIMAL -> targetType == BigDecimal.class;
                        case BIG_INTEGER -> targetType == BigInteger.class;
                        case NUMBER -> Number.class.isAssignableFrom(targetType);
                        case DATE, LOCAL_DATE, LOCAL_TIME, LOCAL_DATE_TIME, ZONED_DATE_TIME, INSTANT, YEAR, YEAR_MONTH,
                                PERIOD, DURATION -> type.name().equals(targetType.getSimpleName()) ||
                                type.name().replace("_", "").equalsIgnoreCase(targetType.getSimpleName());
                        case COLLECTION, LIST, SET, MAP, QUEUE, DEQUE ->
                                type.name().equalsIgnoreCase(targetType.getSimpleName()) ||
                                        java.util.Collection.class.isAssignableFrom(targetType);
                        case ARRAY -> targetType.isArray();
                        default -> true; // 对象转换器支持所有类型
                    };
                });
    }

    @Override
    public int getPriority() {
        return priority.getValue();
    }

    @Override
    public String getName() {
        return TypeConverter.super.getName();
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }

    /**
     * 获取支持的转换类型列表
     * 子类应该重写此方法来指定支持的转换类型
     *
     * @return 支持的转换类型列表
     */
    protected List<ConversionType> getSupportedConversionTypes() {
        return List.of(getConversionType());
    }

    /**
     * 获取转换器的主要转换类型
     *
     * @return 转换类型
     */
    protected abstract ConversionType getConversionType();

    /**
     * 添加监听器
     *
     * @param listener 监听器
     */
    public void addListener(ConversionListener listener) {
        if (listener != null && listener.isEnabled()) {
            listeners.add(listener);
        }
    }

    /**
     * 移除监听器
     *
     * @param listener 监听器
     */
    public void removeListener(ConversionListener listener) {
        listeners.remove(listener);
    }

    /**
     * 清除所有监听器
     */
    public void clearListeners() {
        listeners.clear();
    }

    /**
     * 通知转换开始
     */
    protected void notifyConversionStart(ConversionContext context, Object source) {
        for (ConversionListener listener : listeners) {
            try {
                listener.onConversionStart(context, source);
            } catch (Exception e) {
                log.warn(STRING, e);
            }
        }
    }

    /**
     * 通知转换成功
     */
    protected void notifyConversionSuccess(ConversionContext context, Object source, Object result) {
        for (ConversionListener listener : listeners) {
            try {
                listener.onConversionSuccess(context, source, result);
            } catch (Exception e) {
                log.warn(STRING, e);
            }
        }
    }

    /**
     * 通知转换失败
     */
    protected void notifyConversionFailure(ConversionContext context, Object source, Exception exception) {
        for (ConversionListener listener : listeners) {
            try {
                listener.onConversionFailure(context, source, exception);
            } catch (Exception e) {
                log.warn(STRING, e);
            }
        }
    }

    /**
     * 通知转换完成
     */
    protected void notifyConversionComplete(ConversionContext context, Object source, Object result, Exception exception) {
        for (ConversionListener listener : listeners) {
            try {
                listener.onConversionComplete(context, source, result, exception);
            } catch (Exception e) {
                log.warn(STRING, e);
            }
        }
    }

    /**
     * 通知缓存命中
     */
    protected void notifyCacheHit(ConversionContext context, Object source, Object cachedResult) {
        for (ConversionListener listener : listeners) {
            try {
                listener.onCacheHit(context, source, cachedResult);
            } catch (Exception e) {
                log.warn(STRING, e);
            }
        }
    }

    /**
     * 通知缓存未命中
     */
    protected void notifyCacheMiss(ConversionContext context, Object source) {
        for (ConversionListener listener : listeners) {
            try {
                listener.onCacheMiss(context, source);
            } catch (Exception e) {
                log.warn(STRING, e);
            }
        }
    }

    /**
     * 通知验证开始
     */
    protected void notifyValidationStart(ConversionContext context, Object value) {
        for (ConversionListener listener : listeners) {
            try {
                listener.onValidationStart(context, value);
            } catch (Exception e) {
                log.warn(STRING, e);
            }
        }
    }

    /**
     * 通知验证成功
     */
    protected void notifyValidationSuccess(ConversionContext context, Object value) {
        for (ConversionListener listener : listeners) {
            try {
                listener.onValidationSuccess(context, value);
            } catch (Exception e) {
                log.warn(STRING, e);
            }
        }
    }

    /**
     * 通知验证失败
     */
    protected void notifyValidationFailure(ConversionContext context, Object value, Exception exception) {
        for (ConversionListener listener : listeners) {
            try {
                listener.onValidationFailure(context, value, exception);
            } catch (Exception e) {
                log.warn(STRING, e);
            }
        }
    }
}
